// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: support e2e deadline and liveliness: 1. xml support e2e_deadline and e2e_liveliness config 2. data writer and data reader support e2e deadline and e2e liveliness qos
// feature: another method of counting packet lost
// feature: add fast heartbeat feature
// feature: destination order support by reception timestamp
// feature: QoS Profile Inheritance and Composition
// feature: simplify xml profile
// ------------------------------------------------------------------

#ifndef XMLPARSER_XMLPARSER_H_
#define XMLPARSER_XMLPARSER_H_

#include <map>
#include <string>
#include <unordered_map>
#include <atomic>

#include <xmlparser/attributes/XMLRTPSParticipantAttributes.h>
#include <xmlparser/attributes/XMLTopicAttributes.h>
#include <xmlparser/attributes/XMLPublisherAttributes.h>
#include <xmlparser/attributes/XMLSubscriberAttributes.h>
#include <xmlparser/attributes/XMLParticipantAttributes.h>
#include <xmlparser/attributes/XMLRTPSParticipantAllocationAttributes.hpp>
#include <elog/ReturnCode.hpp>
#include "xmlparser/transport_descriptors/transport_descriptor_interface.h"

namespace tinyxml2 {
class XMLElement;
class XMLDocument;
}  // namespace tinyxml2

namespace vbsutil {
namespace xmlparser {
class BaseNode;
template <class T>
class DataNode;

typedef std::unique_ptr<BaseNode> up_base_node_t;
typedef std::map<std::string, std::string> node_att_map_t;
typedef node_att_map_t::const_iterator node_att_map_cit_t;

typedef std::shared_ptr<TransportDescriptorInterfacePart> sp_transport_t;
typedef std::map<std::string, sp_transport_t> sp_transport_map_t;

typedef std::unique_ptr<ParticipantAttributes> up_participant_t;
typedef DataNode<ParticipantAttributes> node_participant_t;
typedef std::unique_ptr<node_participant_t> up_node_participant_t;

typedef std::unique_ptr<PublisherAttributes> up_publisher_t;
typedef DataNode<PublisherAttributes> node_publisher_t;
typedef std::unique_ptr<node_publisher_t> up_node_publisher_t;

typedef std::unique_ptr<SubscriberAttributes> up_subscriber_t;
typedef DataNode<SubscriberAttributes> node_subscriber_t;
typedef std::unique_ptr<node_subscriber_t> up_node_subscriber_t;

typedef std::unique_ptr<TopicAttributes> up_topic_t;
typedef DataNode<TopicAttributes> node_topic_t;
typedef std::unique_ptr<node_topic_t> up_node_topic_t;

enum ParticipantConfigKind : uint8_t {
    PART_CONFIG_DOMAIN_ID = 0,
    PART_CONFIG_ALLOCATION,
    PART_CONFIG_PREFIX,
    PART_CONFIG_IGN_NON_MATCHING_LOCS,
    PART_CONFIG_DEF_EXT_UNI_LOC_LIST,
    PART_CONFIG_DEF_UNI_LOC_LIST,
    PART_CONFIG_DEF_MULTI_LOC_LIST,
    PART_CONFIG_SEND_SOCK_BUF_SIZE,
    PART_CONFIG_LIST_SOCK_BUF_SIZE,
    PART_CONFIG_BUILTIN,
    PART_CONFIG_PORT,
    PART_CONFIG_PART_ID,
    PART_CONFIG_USER_TRANS,
    PART_CONFIG_BUILTIN_TRANS,
    PART_CONFIG_TRANSPORT_TYPE,
    PART_CONFIG_PROPERTIES_POLICY,
    PART_CONFIG_FLOW_CONTROLLER,
    PART_CONFIG_NAME,
    PART_CONFIG_END
};

enum PublisherConfigKind : uint8_t {
    PUB_CONFIG_SEND_MULTI = 0,
    PUB_CONFIG_HISTORY_QOS,
    PUB_CONFIG_RES_LIMITS_QOS,
    PUB_CONFIG_DURABILITY,
    PUB_CONFIG_LIVELINESS,
    PUB_CONFIG_RELIABILITY,
    PUB_CONFIG_PARTITION,
    PUB_CONFIG_PUB_MODE,
    PUB_CONFIG_DEADLINE,
    PUB_CONFIG_LIFESPAN,
    PUB_CONFIG_DISABLE_POSITIVE_ACKS,
    PUB_CONFIG_OWNERSHIP,
    PUB_CONFIG_OWNERSHIP_STRENGTH,
    PUB_CONFIG_BATCH,
    PUB_CONFIG_DISABLE_HEARTBEAT_PIGGYBACK,
    PUB_CONFIG_E2E_FUNCTION,
    PUB_CONFIG_HEARTBEAT_PER_MAX_SAMPLE,
    PUB_CONFIG_TIMES,
    PUB_CONFIG_IGN_NON_MATCHING_LOCS,
    PUB_CONFIG_EXT_UNI_LOC_LIST,
    PUB_CONFIG_UNI_LOC_LIST,
    PUB_CONFIG_MULTI_LOC_LIST,
    PUB_CONFIG_REM_LOC_LIST,
    PUB_CONFIG_HIST_MEM_POLICY,
    PUB_CONFIG_PROPERTIES_POLICY,
    PUB_CONFIG_USER_DEF_ID,
    PUB_CONFIG_ENTITY_ID,
    PUB_CONFIG_MATCHED_SUBSCRIBERS_ALLOCATION,
    PUB_CONFIG_HIGH_WATERMARK,
    PUB_CONFIG_LOW_WATERMARK,
    PUB_CONFIG_END
};

enum SubscriberConfigKind : uint8_t {
    SUB_CONFIG_SEND_MULTI = 0,
    SUB_CONFIG_HISTORY_QOS,
    SUB_CONFIG_RES_LIMITS_QOS,
    SUB_CONFIG_DURABILITY,
    SUB_CONFIG_LIVELINESS,
    SUB_CONFIG_RELIABILITY,
    SUB_CONFIG_PARTITION,
    SUB_CONFIG_DEADLINE,
    SUB_CONFIG_LIFESPAN,
    SUB_CONFIG_DISABLE_POSITIVE_ACKS,
    SUB_CONFIG_OWNERSHIP,
    SUB_CONFIG_E2E_FUNCTION,
    SUB_CONFIG_TIMES,
    SUB_CONFIG_IGN_NON_MATCHING_LOCS,
    SUB_CONFIG_EXT_UNI_LOC_LIST,
    SUB_CONFIG_UNI_LOC_LIST,
    SUB_CONFIG_MULTI_LOC_LIST,
    SUB_CONFIG_REM_LOC_LIST,
    SUB_CONFIG_HIST_MEM_POLICY,
    SUB_CONFIG_PROPERTIES_POLICY,
    SUB_CONFIG_USER_DEF_ID,
    SUB_CONFIG_ENTITY_ID,
    SUB_CONFIG_MATCHED_PUBLISHERS_ALLOCATION,
    SUB_CONFIG_DESTINATION_ORDER,
    SUB_CONFIG_END
};

/**
 * Class XMLParser, used to load XML data.
 * @ingroup XMLPARSER_MODULE
 */
class XMLParserpart {
 private:
    static XMLP_ret generateProfileByBaseProfile(const std::string& name, const std::string& base_name);

    static std::string getAttributeName(const char* name, tinyxml2::XMLElement* elem);

    static XMLP_ret getXMLSnippetProfileAttributes(tinyxml2::XMLElement* elem, const std::string& profile_name);

    static XMLP_ret getXMLSnippetParticipantAttributes(tinyxml2::XMLElement* elem, ParticipantAttributes& participant,
                                                       const std::string& profile_name, std::vector<bool>& set_flags);

    static XMLP_ret getXMLSnippetPublisherAttributes(tinyxml2::XMLElement* elem, PublisherAttributes& publisher,
                                                     const std::string& profile_name, std::vector<bool>& set_flags);

    static XMLP_ret getXMLSnippetSubscriberAttributes(tinyxml2::XMLElement* elem, SubscriberAttributes& subscriber,
                                                      const std::string& profile_name, std::vector<bool>& set_flags);

#if HAVE_SECURITY
    static std::atomic<bool> enable_security_;

    static std::atomic<bool> enforce_security_;
#endif

 public:
    static std::vector<std::string> parsed_profiles_;

    static std::vector<std::unordered_multimap<std::string, std::string>> parsed_consumers_;

    RTPS_DllAPI static bool isConsumerDuplicate(tinyxml2::XMLElement* consumer);

    RTPS_DllAPI static XMLP_ret loadDefaultXMLFile(vbsutil::xmlparser::up_base_node_t& root);

    RTPS_DllAPI static XMLP_ret loadXML(const std::string& filename, up_base_node_t& root);

    RTPS_DllAPI static XMLP_ret loadXML(const char* data, size_t length, up_base_node_t& root);

    RTPS_DllAPI static XMLP_ret loadXML(tinyxml2::XMLDocument& xmlDoc, up_base_node_t& root);

    static void participantProfileCompareToUpdate(ParticipantAttributes* part_attr, std::vector<bool>& set_flags,
                                                  ParticipantAttributes* snippet_part_attr,
                                                  std::vector<bool>& snippet_set_flags);

    static void publisherProfileCompareToUpdate(PublisherAttributes* pub_attr, std::vector<bool>& set_flags,
                                                PublisherAttributes* snippet_pub_attr,
                                                std::vector<bool>& snippet_set_flags);

    static void subscriberProfileCompareToUpdate(SubscriberAttributes* sub_attr, std::vector<bool>& set_flags,
                                                 SubscriberAttributes* snippet_sub_attr,
                                                 std::vector<bool>& snippet_set_flags);

    RTPS_DllAPI static XMLP_ret parseXMLTransportsProf(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXMLDSFTransportData(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXMLSharedQueueTransportData(tinyxml2::XMLElement* p_root,
                                                                 sp_transport_t p_transport);

    RTPS_DllAPI static XMLP_ret parseXMLParticipantProf(tinyxml2::XMLElement* p_root, BaseNode& rootNode,
                                                        const std::string& profile_lib_name,
                                                        const std::string& profiles_base_name);

    RTPS_DllAPI static XMLP_ret parseXMLPublisherProf(tinyxml2::XMLElement* p_root, BaseNode& rootNode,
                                                      const std::string& profile_lib_name,
                                                      const std::string& profiles_base_name);

    RTPS_DllAPI static XMLP_ret parseXMLSubscriberProf(tinyxml2::XMLElement* p_root, BaseNode& rootNode,
                                                       const std::string& profile_lib_name,
                                                       const std::string& profiles_base_name);

    RTPS_DllAPI static XMLP_ret parseXMLTopicData(tinyxml2::XMLElement* p_root, BaseNode& rootNode);

    /**
     * Load a XML consumer node and parses it. Adds the parsed consumer to Log directly.
     * @param consumer Node to be loaded.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret parseXMLConsumer(tinyxml2::XMLElement& consumer);

    RTPS_DllAPI static void fillBuildinProfilesAttributes();

    RTPS_DllAPI static XMLP_ret fillDataNode(tinyxml2::XMLElement* p_profile,
                                             DataNode<ParticipantAttributes>& participant_node,
                                             const std::string& profiles_base_name, std::vector<bool>& set_flags);

    RTPS_DllAPI static XMLP_ret fillDataNode(tinyxml2::XMLElement* p_profile,
                                             DataNode<PublisherAttributes>& publisher_node,
                                             const std::string& profiles_base_name, std::vector<bool>& set_flags);

    RTPS_DllAPI static XMLP_ret fillDataNode(tinyxml2::XMLElement* p_profile,
                                             DataNode<SubscriberAttributes>& subscriber_node,
                                             const std::string& profiles_base_name, std::vector<bool>& set_flags);

    RTPS_DllAPI static XMLP_ret fillDataNode(tinyxml2::XMLElement* node, DataNode<TopicAttributes>& topic_node);

    template <typename T>
    RTPS_DllAPI static void addAllAttributes(tinyxml2::XMLElement* p_profile, DataNode<T>& node);

    RTPS_DllAPI static XMLP_ret getXMLPropertiesPolicy(tinyxml2::XMLElement* elem,
                                                       xmlparser::PropertyPolicy& propertiesPolicy, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLFlowControllers(
        tinyxml2::XMLElement* elem, std::vector<std::shared_ptr<xmlparser::FlowControllerDescriptor>>& flowControllers,
        uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLHistoryMemoryPolicy(tinyxml2::XMLElement* elem,
                                                          xmlparser::MemoryManagementPolicy_t& historyMemoryPolicy,
                                                          uint8_t ident);

    static XMLP_ret getXMLExternalLocatorList(tinyxml2::XMLElement* elem,
                                              xmlparser::ExternalLocators& external_locators, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLLocatorList(tinyxml2::XMLElement* elem, xmlparser::LocatorList_t& locatorList,
                                                  uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLLocatorUDPv4(tinyxml2::XMLElement* elem, xmlparser::Locator_t& locator,
                                                   uint8_t ident);
    RTPS_DllAPI static XMLP_ret getXMLLocatorUDS(tinyxml2::XMLElement* elem, xmlparser::Locator_t& locator,
                                                 uint8_t ident);
#ifdef VBS_IPV6
    RTPS_DllAPI static XMLP_ret getXMLLocatorUDPv6(tinyxml2::XMLElement* elem, xmlparser::Locator_t& locator,
                                                   uint8_t ident);
#endif
    RTPS_DllAPI static XMLP_ret getXMLLocatorTCPv4(tinyxml2::XMLElement* elem, xmlparser::Locator_t& locator,
                                                   uint8_t ident);
#ifdef VBS_IPV6
    RTPS_DllAPI static XMLP_ret getXMLLocatorTCPv6(tinyxml2::XMLElement* elem, xmlparser::Locator_t& locator,
                                                   uint8_t ident);
#endif
    RTPS_DllAPI static XMLP_ret getXMLWriterTimes(tinyxml2::XMLElement* elem, xmlparser::WriterTimes& times,
                                                  uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLReaderTimes(tinyxml2::XMLElement* elem, xmlparser::ReaderTimes& times,
                                                  uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLDuration(tinyxml2::XMLElement* elem, Duration_t& duration, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLLivelinessKind(tinyxml2::XMLElement* elem, LivelinessQosPolicyKind& kind,
                                                     uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLPublishModeQos(tinyxml2::XMLElement* elem, PublishModeQosPolicy& publishMode,
                                                     uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLPartitionQos(tinyxml2::XMLElement* elem, PartitionQosPolicy& partition,
                                                   uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLOwnershipStrengthQos(tinyxml2::XMLElement* elem,
                                                           OwnershipStrengthQosPolicy& ownershipStrength,
                                                           uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLOwnershipQos(tinyxml2::XMLElement* elem, OwnershipQosPolicy& ownership,
                                                   uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLLifespanQos(tinyxml2::XMLElement* elem, LifespanQosPolicy& lifespan,
                                                  uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLReliabilityQos(tinyxml2::XMLElement* elem, ReliabilityQosPolicy& reliability,
                                                     uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLLivelinessQos(tinyxml2::XMLElement* elem, LivelinessQosPolicy& liveliness,
                                                    uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLDeadlineQos(tinyxml2::XMLElement* elem, DeadlineQosPolicy& deadline,
                                                  uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLDurabilityQos(tinyxml2::XMLElement* elem, DurabilityQosPolicy& durability,
                                                    uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLTopicAttributes(tinyxml2::XMLElement* elem, TopicAttributes& topic,
                                                      uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLHistoryQosPolicy(tinyxml2::XMLElement* elem, HistoryQosPolicy& historyQos,
                                                       uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLResourceLimitsQos(tinyxml2::XMLElement* elem,
                                                        ResourceLimitsQosPolicy& resourceLimitsQos, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLContainerAllocationConfig(tinyxml2::XMLElement* elem,
                                                                ResourceLimitedContainerConfig& resourceLimitsQos,
                                                                uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLPortParameters(tinyxml2::XMLElement* elem, xmlparser::PortParameters& port,
                                                     uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLParticipantAllocationAttributes(
        tinyxml2::XMLElement* elem, xmlparser::RTPSParticipantAllocationAttributes& allocation, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLRemoteLocatorsAllocationAttributes(
        tinyxml2::XMLElement* elem, xmlparser::RemoteLocatorsAllocationAttributes& allocation, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLSendBuffersAllocationAttributes(
        tinyxml2::XMLElement* elem, xmlparser::SendBuffersAllocationAttributes& allocation, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLDiscoverySettings(tinyxml2::XMLElement* elem,
                                                        xmlparser::DiscoverySettings& settings, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLInitialAnnouncementsConfig(tinyxml2::XMLElement* elem,
                                                                 xmlparser::InitialAnnouncementConfig& config,
                                                                 uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLBuiltinAttributes(tinyxml2::XMLElement* elem,
                                                        xmlparser::BuiltinAttributes& builtin, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLOctetVector(tinyxml2::XMLElement* elem,
                                                  std::vector<xmlparser::octet>& octet_vector, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLInt(tinyxml2::XMLElement* elem, int32_t* in, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLUint(tinyxml2::XMLElement* elem, uint32_t* ui, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLUint(tinyxml2::XMLElement* elem, uint16_t* ui16, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLUint64(tinyxml2::XMLElement* elem, uint64_t* ui64, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLFloat(tinyxml2::XMLElement* elem, float* fl, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLBool(tinyxml2::XMLElement* elem, bool* b, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLEnum(tinyxml2::XMLElement* elem, xmlparser::DiscoveryProtocol_t* e,
                                           uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLEnum(tinyxml2::XMLElement* elem, xmlparser::ParticipantFilteringFlags_t* e,
                                           uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLString(tinyxml2::XMLElement* elem, std::string* s, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLDisablePositiveAcksQos(tinyxml2::XMLElement* elem,
                                                             DisablePositiveACKsQosPolicy& disablePositiveAcks,
                                                             uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLguidPrefix(tinyxml2::XMLElement* elem, xmlparser::GuidPrefix_t& prefix,
                                                 uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLParticipantAttributes(tinyxml2::XMLElement* elem,
                                                            ParticipantAttributes& participant,
                                                            std::vector<bool>& set_flags, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLPublisherAttributes(tinyxml2::XMLElement* elem, PublisherAttributes& publisher,
                                                          std::vector<bool>& set_flags, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLSubscriberAttributes(tinyxml2::XMLElement* elem, SubscriberAttributes& subscriber,
                                                           std::vector<bool>& set_flags, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLBatchQos(tinyxml2::XMLElement* elem, BatchQosPolicy& batch, uint8_t ident);

    RTPS_DllAPI static XMLP_ret getXMLDestinationOrderQos(tinyxml2::XMLElement* elem,
                                                          DestinationOrderQosPolicy& destinationOrder);

    RTPS_DllAPI static XMLP_ret getXMLTransports(
        tinyxml2::XMLElement* elem, std::vector<std::string>& transports,
        std::vector<std::shared_ptr<TransportDescriptorInterfacePart>>& transportsDSF, uint8_t ident);

    RTPS_DllAPI static XMLP_ret parseProfiles(tinyxml2::XMLElement* p_root, BaseNode& profilesNode);

    RTPS_DllAPI static XMLP_ret parseXML(tinyxml2::XMLDocument& xmlDoc, vbsutil::xmlparser::up_base_node_t& root);

    RTPS_DllAPI static XMLP_ret parseLogConfig(tinyxml2::XMLElement* p_root);

#if HAVE_SECURITY
    RTPS_DllAPI static void set_security(bool enable);

    RTPS_DllAPI static bool is_security_enabled();

    RTPS_DllAPI static void set_enforce(bool enable);

    RTPS_DllAPI static bool is_enforcing();
#endif
};

}  // namespace xmlparser
}  // namespace vbsutil

#endif  // INCLUDE_ERTPS_XMLPARSER_XMLPARSER_H_
